package com.atguigu.daijia.dispatch.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.daijia.common.constant.RedisConstant;
import com.atguigu.daijia.dispatch.mapper.OrderJobMapper;
import com.atguigu.daijia.dispatch.service.NewOrderService;
import com.atguigu.daijia.dispatch.xxl.client.XxlJobClient;
import com.atguigu.daijia.map.client.LocationFeignClient;
import com.atguigu.daijia.model.entity.dispatch.OrderJob;
import com.atguigu.daijia.model.enums.OrderStatus;
import com.atguigu.daijia.model.form.map.SearchNearByDriverForm;
import com.atguigu.daijia.model.vo.dispatch.NewOrderTaskVo;
import com.atguigu.daijia.model.vo.map.NearByDriverVo;
import com.atguigu.daijia.model.vo.order.NewOrderDataVo;
import com.atguigu.daijia.order.client.OrderInfoFeignClient;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class NewOrderServiceImpl implements NewOrderService {

    @Resource
    private RedisTemplate redisTemplate;
    @Resource
    private OrderJobMapper orderJobMapper;

    @Resource
    private XxlJobClient xxlJobClient;

    @Resource
    private OrderInfoFeignClient orderInfoFeignClient;

    @Resource
    private LocationFeignClient locationFeignClient;

    /*
     * @param newOrderTaskVo
     * @==============History===============<br/>
     * @Description //   添加并开始新订单任务调度
     * @Date 2024-8-25 20:35 
     * @Author < a href="15991488967@163.com">chen</ a>
     * @return java.lang.Long
     */
    @Override
    public Long addAndStartTask(NewOrderTaskVo orderTaskVo)
    {
        // 判断当前这个订单是不是已经开启了订单任务调度去查询满足条件的司机信息,如果没有开启再创建任务并开始执行
        Long orderId = orderTaskVo.getOrderId();// 当前订单的id
        LambdaQueryWrapper<OrderJob> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(OrderJob::getOrderId, orderId);
        OrderJob orderJob = orderJobMapper.selectOne(wrapper);
        if(null == orderJob)
        {
            String executorHandler = "newOrderTaskHandler";// 执行器名称
            String param = "";// 执行器参数
            String corn = "0 0/1 * * * ?";// corn表达式,每1分钟执行一次
            String desc = "新创建订单任务调度:" + orderId;// 执行器描述
            Long jobId = xxlJobClient.addAndStart(executorHandler, param, corn, desc);
            // 记录任务调度信息
            orderJob = new OrderJob();
            orderJob.setJobId(jobId);
            orderJob.setOrderId(orderId);
            orderJob.setParameter(JSONObject.toJSONString(orderTaskVo));
            orderJobMapper.insert(orderJob);
        }
        // 返回任务的id
        return orderJob.getJobId();
    }

    /*
     * @param jobId   任务id
     * @==============History===============<br/>
     * @Description //   执行任务调度,获取满足条件的司机,并且把订单信息设置到司机的队列里面去
     * @Date 2024-8-25 21:03 
     * @Author < a href="15991488967@163.com">chen</ a>
     * @return void
     */
    @Override
    public void executeTask(long jobId)
    {
        // 1 根据jobId查询数据库,当前任务是否已经创建
        //如果没有创建，不往下执行了
        LambdaQueryWrapper<OrderJob> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(OrderJob::getJobId,jobId);
        OrderJob orderJob = orderJobMapper.selectOne(wrapper);
        if(orderJob == null)  return;

        // 2 查询订单状态,如果当前订单接单状态,继续执行。如果当前订单不是接单状态,停止任务调度
        String jsonString = orderJob.getParameter();
        NewOrderTaskVo orderTaskVo = JSONObject.parseObject(jsonString, NewOrderTaskVo.class);
        Long orderId = orderTaskVo.getOrderId();// 订单id
        Integer status = orderInfoFeignClient.getOrderStatus(orderId).getData();
        if(!Objects.equals(status, OrderStatus.WAITING_ACCEPT.getStatus()))
        {
          // 停止任务调度
            xxlJobClient.stopJob(jobId);
            return;
        }

        // 3 远程调用:搜索附近满足条件可以接单司机
        SearchNearByDriverForm searchNearByDriverForm = new SearchNearByDriverForm();
        searchNearByDriverForm.setLongitude(orderTaskVo.getStartPointLongitude());
        searchNearByDriverForm.setLatitude(orderTaskVo.getStartPointLatitude());
        searchNearByDriverForm.setMileageDistance(orderTaskVo.getExpectDistance());
        // 这里的司机都是满足条件的司机
        List<NearByDriverVo> driverVos =
                        locationFeignClient.searchNearByDriver(searchNearByDriverForm).getData();
        if(null != driverVos && driverVos.size() > 0)
        {
            // 对于当前的订单创建一个key
            String repeatKey =
                    RedisConstant.DRIVER_ORDER_REPEAT_LIST + orderId;
            for (NearByDriverVo driver : driverVos)
            {
                // 我们将当前的这个订单推送给当前的司机,不能重复推送给同一个司机。使用set来进行推送
                Long driverId = driver.getDriverId();
                Boolean isMember = redisTemplate.opsForSet().isMember(repeatKey, driverId);
                if(Boolean.FALSE.equals(isMember))
                {
                    redisTemplate.opsForSet().add(repeatKey,driverId);
                    // 过期时间:15分钟,超过15分钟没有接单自动取消
                    redisTemplate.expire(repeatKey,
                                        RedisConstant.DRIVER_ORDER_REPEAT_LIST_EXPIRES_TIME,
                                        TimeUnit.MINUTES);

                    NewOrderDataVo newOrderDataVo = new NewOrderDataVo();
                    newOrderDataVo.setOrderId(orderTaskVo.getOrderId());
                    newOrderDataVo.setStartLocation(orderTaskVo.getStartLocation());
                    newOrderDataVo.setEndLocation(orderTaskVo.getEndLocation());
                    newOrderDataVo.setExpectAmount(orderTaskVo.getExpectAmount());
                    newOrderDataVo.setExpectDistance(orderTaskVo.getExpectDistance());
                    newOrderDataVo.setExpectTime(orderTaskVo.getExpectTime());
                    newOrderDataVo.setFavourFee(orderTaskVo.getFavourFee());
                    newOrderDataVo.setDistance(driver.getDistance());
                    newOrderDataVo.setCreateTime(orderTaskVo.getCreateTime());
                    // 新订单保存司机的临时队列,Redis里面List集合
                    String key = RedisConstant.DRIVER_ORDER_TEMP_LIST + driver.getDriverId();
                    redisTemplate.opsForList().leftPush(key,JSONObject.toJSONString(newOrderDataVo));
                    // 过期时间：1分钟
                    redisTemplate.expire(key,1, TimeUnit.MINUTES);
                }
            }
        }
    }

    /*
     * @param driverId
     * @==============History===============<br/>
     * @Description //   查询司机新订单数据
     * @Date 2024-8-25 21:39
     * @Author < a href="15991488967@163.com">chen</ a>
     * @return java.util.List<com.atguigu.daijia.model.vo.order.NewOrderDataVo>
     */
    @Override
    public List<NewOrderDataVo> findNewOrderQueueData(Long driverId)
    {
        List<NewOrderDataVo> list = new ArrayList<>();
        String key = RedisConstant.DRIVER_ORDER_TEMP_LIST + driverId;
        Long size = redisTemplate.opsForList().size(key);
        if(null != size && size > 0 )
        {
            for (int i = 0; i < size; i++)
            {
                String content = (String) redisTemplate.opsForList().leftPop(key);
                NewOrderDataVo newOrderDataVo = JSONObject.parseObject(content, NewOrderDataVo.class);
                list.add(newOrderDataVo);
            }
        }
        return list;
    }

    /*
     * @param driverId
     * @==============History===============<br/>
     * @Description //   清空当前司机的队列信息
     * @Date 2024-8-25 21:37
     * @Author < a href="15991488967@163.com">chen</ a>
     * @return java.lang.Boolean
     */
    @Override
    public Boolean clearNewOrderQueueData(Long driverId)
    {
        redisTemplate.delete(RedisConstant.DRIVER_ORDER_TEMP_LIST + driverId);
        return true;
    }
}
